<template>
  <el-card class="card" ref="cardRef">
    <el-row align="top" justify="space-between" :gutter="20">
      <el-col :span="6" class="right-border">
        <el-row align="middle" justify="space-between" :gutter="5">
          <el-col :span="14">
            <el-input
                style="width: 100%;"
                v-model="searchName"
                placeholder="搜索名称"
                clearable
            >
              <template #prefix>
                <el-icon><Search /></el-icon>
              </template>
            </el-input>
          </el-col>
          <el-col :span="10">
            <div class="flex items-center justify-end">
              <el-radio-group v-model="expandAll" @change="handleExpandAll">
                <el-radio-button :value="true" label="展开"></el-radio-button>
                <el-radio-button :value="false" label="折叠"></el-radio-button>
              </el-radio-group>
            </div>
          </el-col>
        </el-row>
        <el-row>
          <el-col>
            <el-button class="w-full mt-2.5" type="primary" @click="handleAdd({id: 0})">新增菜单</el-button>
          </el-col>
        </el-row>
        <el-scrollbar :height="cardHeight + 'px'" class="mt-2.5">
          <el-tree
              class="pb-10"
              ref="treeRef"
              :data="menuData"
              :props="defaultProps"
              highlight-current
              default-expand-all
              :expand-on-click-node="false"
              :filter-node-method="filterNode"
              @node-click="handleNodeClick"
          >
            <template #default="{ node, data }">
              <div
                  class="flex items-center justify-between w-full"
                  @mouseenter="handleMouseEnter(data.id)"
                  @mouseleave="handleMouseLeave()"
              >
                <div class="flex items-center gap-1">
                  <el-icon :size="20" v-if="data.icon">
                    <component :is="data.icon" />
                  </el-icon>
                  <el-text line-clamp="1">{{ data.title }}</el-text>
                </div>
                <div class="pr-1.5" v-show="(currentNodeId === data.id || hoverNodeId === data.id) && data.id !== 0">
                  <el-space size="small">
                    <el-tag :type="getTagInfo(data.type).type">
                      {{ getTagInfo(data.type).text }}
                    </el-tag>
                    <el-button type="primary" size="small" circle v-show="data.type === 0" @click.stop="handleAdd(data)">
                      <template #icon>
                        <el-icon color="#fff" :size="20">
                          <Plus />
                        </el-icon>
                      </template>
                    </el-button>
                    <el-popconfirm title="是否删除数据?" @confirm.stop="handleDelete(data.id)">
                      <template #reference>
                        <el-button type="danger" size="small" circle>
                          <template #icon>
                            <el-icon color="#fff" :size="20">
                              <Minus />
                            </el-icon>
                          </template>
                        </el-button>
                      </template>
                    </el-popconfirm>
                  </el-space>
                </div>
              </div>
            </template>
          </el-tree>
        </el-scrollbar>
      </el-col>
      <el-col :span="18">
        <div class="flex items-center justify-between pb-2.5" style="border-bottom: 1px solid var(--el-border-color)">
          <el-text size="large" tag="b">{{ menuName }}</el-text>
          <el-button type="primary" @click="handleSave">保存</el-button>
        </div>
        <el-scrollbar :height="cardHeight + 'px'" class="mt-2.5">
          <div class="mt-2.5 pa-5">
            <el-form ref="formRef" :rules="rules" :model="form" label-width="auto">
              <el-row :gutter="20">
                <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
                  <el-form-item :label="RouteType[form.type].label + '名称'" prop="title">
                    <el-input v-model="form.title" placeholder="请输入菜单名称" clearable @input="handleChangeName"/>
                  </el-form-item>
                </el-col>
                <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
                  <el-form-item label="权限标识" prop="permission">
                    <el-input style="width: 100%;" v-model="form.permission" placeholder="请输入权限标识，此项全局唯一"
                              clearable/>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20" v-if="form.type === 0">
                <!--                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">-->
                <!--                  <el-form-item label="路由名称" prop="name">-->
                <!--                    <el-input v-model="form.name" placeholder="请输入菜单名称" clearable/>-->
                <!--                  </el-form-item>-->
                <!--                </el-col>-->
                <!--                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">-->
                <!--                  <el-form-item label="权限标识" prop="permission">-->
                <!--                    <el-input style="width: 100%;" v-model="form.permission" placeholder="请输入权限标识，此项全局唯一"-->
                <!--                              clearable/>-->
                <!--                  </el-form-item>-->
                <!--                </el-col>-->
              </el-row>
              <el-row :gutter="20">
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                  <el-form-item label="上级菜单" prop="pid">
                    <el-tree-select
                        v-model="form.pid"
                        :data="data"
                        :props="defaultProps"
                        :check-strictly="true"
                        :render-after-expand="false"
                        default-expand-all
                        clearable
                    />
                  </el-form-item>
                </el-col>
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                  <el-form-item label="菜单类型" prop="type">
                    <el-radio-group v-model="form.type" @change="changeMenuType">
                      <el-radio-button :value="item.value" :label="item.label" v-for="(item, key) in RouteType" :key="key" />
                      <!--                      <el-radio-button :value="1">按钮</el-radio-button>-->
                      <!--                      <el-radio-button :value="2">外链</el-radio-button>-->
                      <!--                      <el-radio-button :value="3">iFrame</el-radio-button>-->
                    </el-radio-group>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20" v-show="form.type !== 1">
                <el-col :span="24">
                  <el-form-item label="菜单图标">
                    <el-input v-model="form.icon" placeholder="请输入菜单图标" clearable/>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20" v-if="form.type === 0">
                <el-col :span="24">
                  <el-form-item label="路由地址" prop="route" :rules="[
                    {
                      required: true,
                      message: '页面访问地址，以 / 开头',
                      trigger: 'blur'
                    }
                  ]">
                    <el-input v-model="form.route" placeholder="页面访问地址，以 '/' 开头" clearable/>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20" v-show="form.type === 0">
                <el-col :span="24">
                  <el-form-item label="视图地址" prop="component">
                    <el-input v-model="form.component" placeholder="视图地址，指向模块下的views目录文件" clearable/>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20" v-show="form.type === 0">
                <el-col :span="24">
                  <el-form-item label="路由重定向" prop="redirect">
                    <el-input v-model="form.redirect" placeholder="利用vue-route跳转其他路由地址，以 '/' 开头" clearable/>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20" v-if="[2, 3].includes(form.type)">
                <el-col :span="24">
                  <el-form-item label="链接/iFrame" prop="url" :rules="[
                    {
                      required: true,
                      message: '请输入第三方URL',
                      trigger: 'blur'
                    }
                  ]">
                    <el-input v-model="form.url" placeholder="请输入第三方URL" clearable/>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20">
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                  <el-form-item label="国际化">
                    <el-input v-model="form.i18" placeholder="菜单标题国际化" clearable/>
                  </el-form-item>
                </el-col>
                <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
                  <el-form-item label="排序">
                    <el-input-number style="width: 100%;" v-model="form.order" />
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20">
                <el-col :xs="12" :sm="12" :md="8" :lg="8" :xl="8">
                  <el-form-item label="是否启用">
                    <el-switch v-model="form.status" :active-value="1" :inactive-value="0"/>
                  </el-form-item>
                </el-col>
                <el-col :xs="12" :sm="12" :md="8" :lg="8" :xl="8" v-show="form.type === 0">
                  <el-form-item label="是否显示">
                    <el-switch v-model="form.is_show" :active-value="1" :inactive-value="0"/>
                  </el-form-item>
                </el-col>
                <el-col :xs="12" :sm="12" :md="8" :lg="8" :xl="8" v-show="form.type === 0">
                  <el-form-item label="是否缓存">
                    <el-switch v-model="form.is_cache" :active-value="1" :inactive-value="0" />
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20">
                <el-col :span="24">
                  <el-form-item label="备注" prop="desc">
                    <el-input type="textarea" v-model="form.desc"/>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20" v-show="form.type === 0">
                <el-col :span="24">
                  <el-form-item label="按钮权限" prop="desc">
                    <el-table :data="form.buttons" size="small" border style="width: 100%">
                      <el-table-column align="center" width="100">
                        <template #header>
                          <el-button type="primary" size="small" circle @click="onAddButton">
                            <template #icon>
                              <el-icon color="#ffffff" :size="20">
                                <Plus />
                              </el-icon>
                            </template>
                          </el-button>
                        </template>
                        <template #default="scope">
                          <el-popconfirm title="是否删除数据?" @confirm.stop="deleteButton(scope.row.id)">
                            <template #reference>
                              <el-button type="danger" size="small" circle>
                                <template #icon>
                                  <el-icon color="#ffffff" :size="20">
                                    <Minus />
                                  </el-icon>
                                </template>
                              </el-button>
                            </template>
                          </el-popconfirm>
                        </template>
                      </el-table-column>
                      <el-table-column prop="name" label="按钮名称">
                        <template #default="scope">
                          <el-input v-model="scope.row.title" type="text" placeholder="请输入按钮名称" />
                        </template>
                      </el-table-column>
                      <el-table-column prop="permission" label="按钮标识">
                        <template #default="scope">
                          <el-input v-model="scope.row.permission" type="text" placeholder="请输入按钮标识" />
                        </template>
                      </el-table-column>
                      <el-table-column prop="state" label="按钮国际化">
                        <template #default="scope">
                          <el-input v-model="scope.row.i18" type="text" placeholder="请输入按钮国际化" />
                        </template>
                      </el-table-column>
                      <template #empty>
                        <div class="flex items-center justify-center">
                          <el-text tag="b">没有按钮菜单?</el-text>
                          <el-button class="ml-2.5" type="primary" plain @click="onAddButton">新增一个</el-button>
                        </div>
                      </template>
                    </el-table>
                  </el-form-item>
                </el-col>
              </el-row>
            </el-form>
          </div>
        </el-scrollbar>
      </el-col>
    </el-row>
  </el-card>
</template>

<script setup lang="ts">
import {ref, onMounted, watch, reactive, computed} from 'vue';
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
import { getMenuList, saveMenuInfo, updateMenuInfo, deleteMenu } from "@/api/menu";

interface Tree {
  name?: any;
  id?: number;
  title?: string;
  value?: number;
  label?: string;
  children?: Tree[]
}

// 配置项
const defaultProps = {
  value: 'id', // 选中值的字段
  label: 'title', // 显示文本的字段
  children: 'children', // 子节点的字段
};

const initData: Tree[] = [
  { id: 0, title: '顶级菜单' }
]

const data = ref<Tree[]>(initData);
// 左侧菜单数据
const menuData = ref<Tree[]>([]);

const searchName = ref('');
const expandAll = ref(true);
const treeRef = ref(null);
const menuName = ref('新增顶级菜单');
// 当前选中ID节点
const currentNodeId = ref(null);
// hover节点ID
const hoverNodeId = ref(null);
// 创建一个 ref 来引用 DOM 元素
const cardRef = ref(null);
// 创建一个 ref 来存储元素的高度
const cardHeight = ref<number>(0);
const formRef = ref<FormInstance>()
// 表单
const initForm = reactive({
  id: null,
  name: '',
  title: '',
  permission: '',
  type: 0,
  pid: 0,
  icon: '',
  route: '',
  redirect: '',
  component: '',
  order: 1,
  status: 1,
  is_show: 1,
  is_cache: 1,
  url: '',
  desc: '',
  i18: '',
  buttons: [],
})
const form = reactive({...initForm})

const RouteType = ref([
  {label: '菜单', value: 0},
  {label: '按钮', value: 1},
  {label: '外链', value: 2},
  {label: 'iFrame', value: 3}
])

// 表单验证
const rules = reactive<FormRules>({
  name: [
    {required: true, message: '请输入菜单名称', trigger: 'blur'},
  ],
  permission: [
    {required: true, message: '请输入菜单标识，此项全局唯一', trigger: 'blur'},
  ],
  title: [
    {required: true, message: '请输入标题', trigger: 'blur'},
  ]
})

// 点击节点事件
const handleNodeClick = (data) => {
  // 标题设置为菜单名称
  menuName.value = data.title;
  // 当前选中节点
  currentNodeId.value = data.id;
  const filteredSource = { ...data }
  Object.assign(form, filteredSource);
}

// 当鼠标移入节点时，记录当前节点ID
const handleMouseEnter = (id) => {
  hoverNodeId.value = id;
}

// 当鼠标移出节点时，清空悬停节点ID
const handleMouseLeave = () => {
  hoverNodeId.value = null;
}

// 展开/折叠全部节点
const handleExpandAll = () => {
  const nodes = treeRef.value.store._getAllNodes();
  nodes.forEach(item => {
    item.expanded = expandAll.value;
  });
}

// 搜索筛选
const filterNode = (value: string, data: Tree) => {
  if (!value) return true
  return data.name.includes(value)
}

// 新增一个按钮权限
const onAddButton = () => {
  form.buttons.push({
    name: '',
    permission: '',
    i18: ''
  })
}

// 删除一个按钮权限
const deleteButton = async (id: number) => {
  // 找到 id 对应的索引
  const index = form.buttons.findIndex(button => button.id === id);

  // 如果找到索引，则删除对应的数据
  if (index !== -1) {
    form.buttons.splice(index, 1);
    await deleteMenu(id);
    ElMessage.success('删除按钮权限成功');
    await handleGetMenuList();
  } else {
    ElMessage.error(`未找到 id 为 ${id} 的按钮`);
  }
};

// 菜单类型改变事件
const changeMenuType = (value: string | number | boolean) => {
  console.log(value)
}

// 菜单标题改变事件
const handleChangeName = (value: string) => {
  menuName.value = value;
}

// 添加菜单
const handleAdd = (data: any) => {
  // 清空表单数据
  formRef.value.resetFields();
  // 重置表单
  Object.assign(form, initForm);
  delete form.id
  // 顶部标题更改为当前选中菜单名称
  menuName.value = '新菜单';
  form.title = '新菜单';
  // 获取当前节点id作为父级菜单
  form.pid = data.id
}

//  保存事件
const handleSave = async () => {
  if (!formRef.value) return;

  // 验证表单
  await formRef.value.validate();
  if(form.id !== null && form.id !== undefined){
    // 编辑修改菜单
    await updateMenuInfo(form.id, form);
    ElMessage.success('编辑成功');
  } else {
    // 添加菜单
    await saveMenuInfo(form);
    ElMessage.success('保存成功');
  }
  await handleGetMenuList();
}

// 删除菜单事件
const handleDelete = async (id: number) => {
  await deleteMenu(id)
  ElMessage.success('删除成功');
  await handleGetMenuList();
}

// 获取菜单列表
const handleGetMenuList = async () => {
  const response = await getMenuList();
  const backendData = response.data;
  data.value = [...initData, ...backendData];
  menuData.value = backendData;
}

const getTagInfo = (type) => {
  const typeMapping = {
    0: { type: 'primary', text: '菜单' },
    1: { type: 'danger', text: '按钮' },
    2: { type: 'success', text: '外链' },
    3: { type: 'warning', text: 'iFrame' },
  };
  return typeMapping[type] || { type: 'info', label: '未知状态' };
}

// 当组件挂载后执行此函数以获取元素的高度
onMounted(() => {
  if (cardRef.value.$el) {
    // 减去card padding 40 && searchForm 32
    cardHeight.value = cardRef.value.$el.offsetHeight - 72;
  }
  handleGetMenuList();
})

watch(searchName, (val) => {
  treeRef.value!.filter(val);
})
</script>

<style lang="scss">
.card {
  position: relative;
  height: 100%;
  overflow: hidden;
}

.el-tree-node__content {
  height: 35px !important;
}

.right-border {
  border-right: 1px solid var(--el-border-color);
}
</style>